<script setup>
import {ElMessage} from "element-plus";
import {checkFile, uploadChunkList} from "@/api/file.js";
import {getChunkList, getHash} from "@/common/utils/utils.js";
import {baseURL} from "@/request/request.js";
import {ref} from "vue";

//视频地址
const url = defineModel('url', {type: String})
//分片尺寸
const chuckSize = 1024 * 1024 * 5;
// 上传状态和进度
const uploading = ref(false);
const uploadProgress = ref(0);
const uploadStatus = ref('');

//文件上传
const upload = async (e) => {
  if (!e.target.files[0]) {
    return
  }
  const file = e.target.files[0];
  if (!file.type.includes('video')) {
    ElMessage({
      type: 'error',
      message: '文件格式错误，请上传视频类型',
    })
    return;
  }
  //判断文件后缀
  if (!file.name.includes('.')) {
    ElMessage({
      type: 'error',
      message: '文件格式错误',
    })
    return;
  }

  uploading.value = true;
  uploadProgress.value = 0;
  uploadStatus.value = '准备上传...';

  try {
    await handleFileUpload(file);
  } catch (error) {
    ElMessage.error('上传失败: ' + error.message);
  } finally {
    uploading.value = false;
  }

  // 清空文件输入框，以便用户可以再次选择相同的文件
  e.target.value = '';
}

// 处理文件上传
const handleFileUpload = async (file) => {
  uploadStatus.value = '计算文件哈希...';
  const chunkList = getChunkList(file, chuckSize);
  const md5 = await getHash(chunkList)
  uploadStatus.value = '检查文件状态...';
  const {data} = await checkFile(md5)

  if (data.url) {
    url.value = baseURL + data.url
    uploadProgress.value = 100;
    uploadStatus.value = '上传完成 (100%)';
    return
  }

  if (data.index) {
    // 已上传部分进度计算
    const progress = Math.floor((data.index / chunkList.length) * 100);
    uploadProgress.value = progress;
    uploadStatus.value = `断点续传 (${progress}%)`;
    await uploadChunk(file, chunkList, md5, data.index)
    return
  }

  uploadStatus.value = '开始上传 (0%)';
  await uploadChunk(file, chunkList, md5)
}

//分片上传
const uploadChunk = async (file, chunkList, md5, index = 0) => {
  const fileName = file.name
  const fileType = file.type
  const size = file.size
  const total = chunkList.length;

  for (index; index < total; index++) {
    const formData = new FormData()
    formData.append('file', chunkList[index])
    formData.append('fileName', fileName)
    formData.append('fileType', fileType)
    formData.append('index', index)
    formData.append('size', size)
    formData.append('md5', md5)
    formData.append('total', total)

    // 更新进度状态
    const progress = Math.floor((index / total) * 100);
    uploadProgress.value = progress;
    uploadStatus.value = `正在上传 (${progress}%)`;

    const {code, data, msg} = await uploadChunkList(formData)
    if (code === 200) {
      url.value = baseURL + data.url
      uploadProgress.value = 100;
      uploadStatus.value = '上传完成 (100%)';
    } else if (code === 400) {
      uploadStatus.value = '上传失败: ' + msg;
      ElMessage.error(msg)
      break;
    }
  }
}

// 取消上传
const cancelUpload = () => {
  if (uploading.value) {
    ElMessage({
      type: 'warning',
      message: '上传已取消',
    });
    uploading.value = false;
    uploadProgress.value = 0;
    uploadStatus.value = '';
  }
}

</script>

<template>
  <div class="content">
    <div v-if="url" class="video-container">
      <video :src="url" controls class="video"></video>
      <el-icon @click="url = ''" class="close">
        <Close/>
      </el-icon>
    </div>
    <div v-else-if="uploading" class="upload-progress">
      <div class="progress-header">
        <span class="status-text">{{ uploadStatus }}</span>
        <span class="percentage">{{ uploadProgress }}%</span>
      </div>
      <el-progress
          :percentage="uploadProgress"
          :status="uploadProgress === 100 ? 'success' : ''"
          :stroke-width="6"
          :show-text="false"
          class="progress">
      </el-progress>
      <el-button type="danger" size="small" @click="cancelUpload" class="cancel-btn">
        取消上传
      </el-button>
    </div>
    <el-button v-else type="primary" class="btn">
      上传视频<input type="file" accept="video/*" @change="upload" class="upload"/>
    </el-button>
  </div>
</template>

<style scoped lang="scss">
.content {
  position: relative;

  .video-container {
    width: 100%;
    max-width: 640px;
    position: relative;

    &:hover {
      .close {
        opacity: 1;
      }
    }

    .video {
      width: 100%;
      display: block;
    }

    .close {
      position: absolute;
      right: 10px;
      top: 10px;
      cursor: pointer;
      font-size: 22px;
      opacity: 0;
      transition: opacity 0.2s;
      background-color: rgba(0, 0, 0, 0.5);
      color: white;
      border-radius: 50%;
      padding: 4px;
      z-index: 10;
    }
  }

  .upload-progress {
    width: 100%;
    max-width: 400px;
    padding: 12px 15px;
    border-radius: 4px;
    background-color: #f5f7fa;
    margin-bottom: 10px;

    .progress-header {
      display: flex;
      justify-content: space-between;
      align-items: center;
      margin-bottom: 8px;

      .status-text {
        font-size: 13px;
        color: #606266;
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
        max-width: 80%;
      }

      .percentage {
        font-size: 13px;
        font-weight: bold;
        color: #409eff;
      }
    }

    .progress {
      margin-bottom: 10px;
    }

    .cancel-btn {
      padding: 5px 12px;
      font-size: 12px;
    }
  }

  .btn {
    position: relative;

    .upload {
      position: absolute;
      width: 100%;
      height: 100%;
      left: 0;
      top: 0;
      opacity: 0;
      cursor: pointer;
    }
  }
}
</style>
